//
//  Vertex3.m
//  CompGraf2
//
//  Created by Juan Niosi on 05/10/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "Vector3.h"

@implementation Vector3

- (id)init
{
    self = [super init];
    if (self) 
    {
        vertices = malloc(sizeof(GLfloat)*3);
        vertices[0] = 0;
        vertices[1] = 0;
        vertices[2] = 0;
    }
    
    return self;
}

- (id)init:(GLfloat)x:(GLfloat)y:(GLfloat)z
{
    self = [super init];
    if (self) 
    {
        vertices = malloc(sizeof(GLfloat)*3);
        vertices[0] = x;
        vertices[1] = y;
        vertices[2] = z;
    }
    
    return self;
}

- (id)init:(GLfloat *)verts
{
    self = [super init];
    if (self) 
    {       
        vertices = malloc(sizeof(GLfloat)*3);
        vertices[0] = verts[0];
        vertices[1] = verts[1];
        vertices[2] = verts[2];
    }
    
    return self;
}

- (GLfloat *)getValues
{
    return vertices;
}

- (GLfloat)getX
{
    return vertices[0];
}

- (GLfloat)getY
{
    return vertices[1];
}

- (GLfloat)getZ
{
    return vertices[2];
}

- (void)setX:(GLfloat)x
{
    vertices[0] = x;
}

- (void)setY:(GLfloat)y
{
    vertices[1] = y;
}

- (void)setZ:(GLfloat)z
{
    vertices[2] = z;
}

- (void)normalize
{
    GLfloat length = [self length];
    vertices[0] /= length;
    vertices[1] /= length;
    vertices[2] /= length;
}

- (GLfloat)length
{
    return sqrtf( vertices[0]* vertices[0] +  vertices[1]*  vertices[1] +  vertices[2]* vertices[2]);
}

- (GLfloat)length2
{
    return  vertices[0]* vertices[0] +  vertices[1]*  vertices[1] +  vertices[2]* vertices[2];
}

- (void)scale:(GLfloat)scale
{
    vertices[0] *= scale;
    vertices[1] *= scale;
    vertices[2] *= scale;
}

- (BOOL)equals:(Vector3 *)vec setDelta:(GLfloat)delta
{
    if ([self getX] - [vec getX] > delta)
        return false;
    
    if ([self getY] - [vec getY] > delta)
        return false;
    
    if ([self getZ] - [vec getZ] > delta)
        return false;
    
    return true;
}

- (BOOL)equals:(Vector3 *)vec
{
    return [self equals:vec setDelta:0.01f];
}

- (Vector3 *)copy
{
    GLfloat *verts = malloc(sizeof(GLfloat)*3);
    verts[0] = vertices[0];
    verts[1] = vertices[1];
    verts[2] = vertices[2];
    return [[Vector3 alloc] init:verts];
}

+ (Vector3 *)add:(Vector3 *)a:(Vector3 *)b
{
    Vector3 *result = [[Vector3 alloc] init:[a getX]+[b getX] :[a getY]+[b getY] :[a getZ]+[b getZ]];
    return result;
}

+ (Vector3 *)subtract:(Vector3 *)a:(Vector3 *)b
{
    return [[Vector3 alloc] init:[a getX]-[b getX] :[a getY]-[b getY] :[a getZ]-[b getZ]];
}

+ (Vector3 *)yRotationToVec3:(GLfloat)angle
{
    float rads = angle * 3.14f  / 180.0f;
    return [[Vector3 alloc] init:cosf(rads) :0 :-sinf(rads)];
}

+ (Vector3 *)lerp:(Vector3 *)from:(Vector3 *)to:(float)delta
{
    Vector3 *dir = [Vector3 subtract:to :from];
    [dir  scale:delta];
    
    return [Vector3 add:from :dir];
}

+ (float)dot:(Vector3 *)a:(Vector3 *)b
{
    return [a getX]*[b getX] + [a getY]*[b getY] + [a getZ]*[b getZ];
}

+ (float)dotXZ:(Vector3 *)a:(Vector3 *)b
{
    return ([a getX]*[b getX] + [a getZ]*[b getZ]);
}

+ (float)angle:(Vector3 *)a:(Vector3 *)b
{
    Vector3 *ac = [a copy];
    Vector3 *bc = [b copy];
    [ac normalize];
    [bc normalize];
    
    return (atan2([b getZ],[b getX]) - atan2([a getZ],[a getX]))*180.0f / 3.14f;
}

+ (Vector3 *)cross:(Vector3 *)ac:(Vector3 *)bc
{
    Vector3 *a = [ac copy];
    Vector3 *b = [bc copy];
    Vector3 *cr = [[Vector3 alloc] init];
    [cr setX:[a getY]*[b getZ] - [b getY]*[a getZ]];
    [cr setY:[a getZ]*[b getX] - [b getZ]*[a getX]];
    [cr setZ:[a getX]*[b getY] - [b getX]*[a getY]];
    return cr;
}

+ (Vector3 *)scale:(Vector3 *)vec:(GLfloat)factor
{
    return [[Vector3 alloc] init:[vec getX]*factor :[vec getY]*factor :[vec getZ]*factor];
}

+ (Vector3 *)up
{
    return [[Vector3 alloc] init:0 :1 :0];
}

+ (Vector3 *)zero
{
    return [[Vector3 alloc] init:0 :0 :0];
}

- (NSString *)toString
{
    return [[NSString alloc] initWithFormat:@"%f %f %f",vertices[0],vertices[1],vertices[2]];
}

- (void)dealloc
{
    free(vertices);
    
    [super dealloc];
}
@end
